通过 SetFinalizer 在error 回收的时候,确认,错误有没被使用过,即调用 Error() 或者 Unwrap() 接口。
以确保,在不需要逐层打印错误的情况下。可以无脑返回错误信息。但是在最上层,将错误打印出来。
最外层,是最先被GC 到的。所以整个逻辑上来说,是没问题的。
应该要考虑的可能是对性能的损耗,待有空,再做压测吧。
我们先"优雅" 地将错误一层层包下去
简单实现示意
package main
import (
"errors"
"fmt"
"runtime"
"time"
)
type errWrap struct {
err error
message string
isUse bool
}
func (e *errWrap) Error() string {
runtime.SetFinalizer(e, nil)
return e.message + " " + e.err.Error()
}
func (e *errWrap) Unwrap() error {
runtime.SetFinalizer(e, nil)
return e.err
}
func Wrap(msg string, err error) error {
e := &errWrap{err: err, message: msg}
runtime.SetFinalizer(e, func(w *errWrap) {
if w.isUse {
return
}
fmt.Printf("error %s\n", w)
})
return e
}
func do() {
err := fmt.Errorf("hello")
err2 := Wrap("wrap", err)
Wrap("wrap never use", err)
fmt.Printf("err %s\n", err2)
fmt.Printf("err %s\n", errors.Unwrap(err2))
err = nil
err2 = nil
}
func main() {
do()
runtime.GC()
time.Sleep(time.Second * 1)
}
注意: Wrap(“wrap never use”, err) 这行包的错误,从来没有使用。在实际中,他就是被遗忘的错误。
导致结果就是,没有人能注意到它们。
爱的反面,不是恨(打日志),而是遗忘(啥也没有)
参考: